namespace VolleyballHall
{
    using System.Collections.Generic;

    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Graphics;
    using Microsoft.Xna.Framework.Input;

    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game : Microsoft.Xna.Framework.Game
    {
        readonly GraphicsDeviceManager graphics;

        Matrix worldMatrix;
        Matrix viewMatrix;
        Matrix projectionMatrix;
        VertexPositionNormalTexture[] modelVertices;

        Effect effect;


        List<Model> model;
        Camera camera;

        public Game()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            worldMatrix = Matrix.Identity;
            camera = new Camera();
            viewMatrix = Matrix.CreateLookAt(camera.Position, camera.Position + camera.LookAt, camera.Up);

            Window.Title = "Projekt 1 - Grafika komputerowa 3D - Patrycja Skorupa";

            model = new List<Model>();

            projectionMatrix = Matrix.CreatePerspectiveFieldOfView(
                MathHelper.ToRadians(45),  // 45 degree angle
                this.GraphicsDevice.Viewport.Width /
                (float)GraphicsDevice.Viewport.Height,
                1.0f, 500.0f);


            var vertices = new List<VertexPositionNormalTexture>();

            vertices.AddRange(ModelCreator.GetCuboid(new Vector3(300, 180, 60), Vector3.Zero, -1));

            vertices.AddRange(ModelCreator.GetNet().TransformPositionBy(Matrix.CreateTranslation(0, 0, -30)));

            vertices.AddRange(ModelCreator.GetBench().TransformPositionBy(Matrix.CreateTranslation(-40, 80, -30)));
            vertices.AddRange(ModelCreator.GetBench().TransformPositionBy(Matrix.CreateTranslation(40, 80, -30)));

            modelVertices = vertices.ToArray();


            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.1
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            effect = Content.Load<Effect>("ShadingEffect");
            var lamp = Content.Load<Model>("lamp");
            ModelCreator.PrepareLamp(lamp, effect);
            model.Add(lamp);
            var humanOne = Content.Load<Model>("human");
            ModelCreator.PrepareHuman(humanOne, effect);
            model.Add(humanOne);
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {

        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            if (Keyboard.GetState().IsKeyDown(Keys.Left))
            {
                camera.RotateLeft();
                viewMatrix = camera.CreateViewMatrix();
            }

            if (Keyboard.GetState().IsKeyDown(Keys.Right))
            {
                camera.RotateRight();
                viewMatrix = camera.CreateViewMatrix();
            }

            if (Keyboard.GetState().IsKeyDown(Keys.Up))
            {
                camera.RotateUp();
                viewMatrix = camera.CreateViewMatrix();
            }

            if (Keyboard.GetState().IsKeyDown(Keys.Down))
            {

                camera.RotateDown();
                viewMatrix = camera.CreateViewMatrix();
            }


            if (Keyboard.GetState().IsKeyDown(Keys.A))
            {
                camera.MoveLeft();
                viewMatrix = camera.CreateViewMatrix();
            }

            if (Keyboard.GetState().IsKeyDown(Keys.D))
            {
                camera.MoveRight();
                viewMatrix = camera.CreateViewMatrix();
            }

            if (Keyboard.GetState().IsKeyDown(Keys.W))
            {
                camera.MoveUp();
                viewMatrix = camera.CreateViewMatrix();
            }

            if (Keyboard.GetState().IsKeyDown(Keys.S))
            {
                camera.MoveDown();
                viewMatrix = camera.CreateViewMatrix();
            }




            base.Update(gameTime);
        }

        private float s;

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);


            graphics.GraphicsDevice.Clear(Color.SteelBlue);

            var rasterizerState1 = new RasterizerState { CullMode = CullMode.None };
            graphics.GraphicsDevice.RasterizerState = rasterizerState1;

            effect.Parameters["World"].SetValue(worldMatrix);
            effect.Parameters["View"].SetValue(viewMatrix);
            effect.Parameters["Projection"].SetValue(projectionMatrix);

            effect.Parameters["activePointLights"].SetValue(1);

            effect.Parameters["LightPointPosition"].SetValue(new[] { new Vector3(0, 89, -9f) });
            effect.Parameters["LightPointColor"].SetValue(new[] { new Vector4(0f, 0.5f, 0f, 1) });


            effect.Parameters["activeSpotLights"].SetValue(2);

            effect.Parameters["lightSpotDirection"].SetValue(new[] { new Vector3(1, 1, -1), new Vector3(0, -1, -1) });
            effect.Parameters["lightSpotDecayExponent"].SetValue(new float[] { 1, 1 });
            effect.Parameters["lightSpotAngleCosine"].SetValue(new[] { 0.5f, 0.5f });


            s += 0.002f;

            effect.Parameters["LightSpotPosition"].SetValue(new[] { new Vector3(-100, -85, 25f), new Vector3(100, 85, 25f) });
            effect.Parameters["LightSpotColor"].SetValue(new[] { new Vector4(1-s, 1 - s, 1 - s, 1), new Vector4(1f, 1f, 1f, 1) });
            
            if (s > 1) s = 0;

            effect.Parameters["SpecularColor"].SetValue(new Vector4(1f, 1f, 1f, 1));
            effect.Parameters["SpecularIntensity"].SetValue(0.7f);
            effect.Parameters["SpecularPower"].SetValue(141f);

            effect.Parameters["AmbientColor"].SetValue(new Vector4(1f, 1f, 1f, 1));
            effect.Parameters["AmbientIntensity"].SetValue(0.05f);

            effect.Parameters["DiffuseIntensity"].SetValue(0.2f);


            effect.Parameters["camPosition"].SetValue(camera.Position);





            foreach (EffectPass pass in effect.CurrentTechnique.Passes)
            {
                pass.Apply();

                graphics.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, modelVertices,
                                                           0, modelVertices.Length / 3);
            }

            foreach (var m in model)
                foreach (var mesh in m.Meshes)
                {
                    mesh.Draw();
                }

            base.Draw(gameTime);
        }
    }
}
